#!/bin/bash -
# @configure_input@
# virt-p2v-make-disk
# Copyright (C) 2014-2019 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

unset CDPATH

program="virt-p2v-make-disk"
version="@PACKAGE_VERSION@"

if [ -n "$VIRT_P2V_DATA_DIR" ]; then
    datadir="$VIRT_P2V_DATA_DIR"
    libdir="$VIRT_P2V_DATA_DIR"
else
    datadir="@datadir@/virt-p2v"
    libdir="@libdir@/virt-p2v"
fi

# Parse the command line arguments.
shortopts=o:vV
longopts=arch:,help,short-options,inject-ssh-identity:,install:,long-options,no-warn-if-partition,output:,verbose,version
TEMP=`getopt \
        -o "$shortopts" \
        --long "$longopts" \
        -n $program -- "$@"`
if [ $? != 0 ]; then
    echo "$program: problem parsing the command line arguments"
    exit 1
fi
eval set -- "$TEMP"

output=
upload=
verbose=
declare -a passthru

usage ()
{
    echo "Usage:"
    echo "  $program [--options] -o /dev/sdX [os-version]"
    echo
    echo "Read $program(1) man page for more information."
    exit $1
}

while true; do
    case "$1" in
        --arch)
            arch="$2"
            shift 2;;
        --inject-ssh-identity)
            upload="--upload $2:/var/tmp/id_rsa"
            shift 2;;
        -o|--output)
            output="$2"
            shift 2;;
        -v|--verbose)
            set +x
            verbose=1
            shift;;

        # virt-builder parameters that are passed through.
        --install)
            passthru[${#passthru[*]}]="$1"
            passthru[${#passthru[*]}]="$2"
            shift 2;;

        --no-warn-if-partition)
            passthru[${#passthru[*]}]="$1"
            shift;;

        # help etc.
        --help)
            usage 0;;
        -V|--version)
            echo "$program $version"
            exit 0;;
        --short-options)
            echo -n "$shortopts" |
                @SED@ -e 's/://g' -e 's/\(.\)/-\1\n/g'
            exit 0;;
        --long-options)
            echo "$longopts" |
                @SED@ -e 's/,/\n/g' -e 's/:$//mg' -e 's/\(.*\)/--\1/mg' |
                grep -v -E -- "--(short|long)-options"
            exit 0;;
        --)
            shift
            break;;
        *)
            echo "internal error ($1)"
            exit 1;;
    esac
done

if [ -z "$output" ]; then
    echo "$program: You must set the -o (--output) option."
    exit 1
fi

if [ $# -gt 1 ]; then
    echo "$program: Too many parameters.  See $program(1)."
    exit 1
fi

if [ $# -eq 1 ]; then
    osversion="$1"
else
    # If osversion was not set, then we must guess a good value
    # based on the host distro.
    if test -f /etc/os-release; then
        osversion="`. /etc/os-release && echo ${ID}-${VERSION_ID}`"
    fi
    if [ "x$osversion" = "x" ]; then
        echo "$program: unable to guess a suitable os-version."
        echo "You must supply one on the command line and output of 'virt-builder -l'."
        echo "See $program(1) for further details."
        exit 1
    fi
fi

if [ -n "$arch" ]; then
    arch_option="--arch $arch"
    virt_p2v_xz_binary="$libdir/virt-p2v.$arch.xz"
else
    virt_p2v_xz_binary="$libdir/virt-p2v.xz"
fi

if [ ! -f "$virt_p2v_xz_binary" ]; then
    echo "$program: cannot find $virt_p2v_xz_binary"
    if [ -n "$arch" ]; then
        echo "You used the '--arch' option, so it’s likely that you will need to build"
        echo "a virt-p2v.$arch binary yourself."
        echo "See p2v-building(1) section BUILDING i686 32 BIT VIRT-P2V for help."
    fi
    exit 1
fi

# Create a temporary directory and clean it up when we finish.
tmpdir="$(mktemp -d)"
cleanup ()
{
    rm -rf $tmpdir
}
trap cleanup INT QUIT TERM EXIT ERR

# Uncompress the virt-p2v binary into tmpdir.
virt_p2v_binary="$tmpdir/virt-p2v"
xzcat "$virt_p2v_xz_binary" > "$virt_p2v_binary"

# Variations depending on the target distro.  The main difference
# is in the list of distro packages we add to the base appliance.
case "$osversion" in
    centos-*|fedora-*|rhel-*|scientificlinux-*|oraclelinux-*)
        depsfile="$datadir/dependencies.redhat"
        cat > $tmpdir/p2v.conf <<'EOF'
add_drivers+=" usb-storage "
EOF
        cat > $tmpdir/post-install <<'EOF'
#!/bin/bash
# Rebuild the initramfs.
latest_version="$(cd /lib/modules; ls -1vr | head -1)"
dracut -v -f --kver $latest_version
EOF
        # Double quotes because we want $tmpdir to be expanded:
        extra_args="
          --selinux-relabel
          --upload $tmpdir/p2v.conf:/etc/dracut.conf.d/
          --run $tmpdir/post-install
        "
        ;;
    debian-*|ubuntu-*)
        depsfile="$datadir/dependencies.debian"
        cat > $tmpdir/policy-rc.d <<'EOF'
#!/bin/sh
# Avoid running daemons during the upgrade/installation
exit 101
EOF
        chmod +x $tmpdir/policy-rc.d
        # Double quotes because we want $tmpdir to be expanded:
        preinstall_args="
          --upload $tmpdir/policy-rc.d:/usr/sbin/policy-rc.d
        "
        final_args="
          --delete /usr/sbin/policy-rc.d
        "
        ;;
    archlinux-*)
        depsfile="$datadir/dependencies.archlinux"
        ;;
    opensuse-*|suse-*)
        depsfile="$datadir/dependencies.suse"
        ;;
    *)
        echo "$program: internal error: could not work out the Linux distro from '$osversion'"
        exit 1
esac

# Virt-builder requires the dependencies to be comma-separated with
# no spaces.  The $depsfile is one dependency per line.
if [ ! -f "$depsfile" ]; then
    echo "$program: cannot find dependencies file ($depsfile)"
    exit 1
fi
install=
while read line; do
    if [ -n "$line" ]; then
        if [ -z "$install" ]; then
            install="$line"
        else
            install="$install,$line"
        fi
    fi
done < $depsfile

# Add -v -x if we're in verbose mode.
if [ "x$verbose" = "x1" ]; then
    verbose_option="-v -x"
fi

# Run virt-builder.  Note we controversially assume systemd here.  We
# could provide a sysvinit fallback if required.
# The manual 'hostname' invocation is needed to set the hostname
# also for the appliance itself, so scriptlets can properly use
# the hostname we want.
virt-builder "$osversion"                                       \
    $verbose_option						\
    --output "$output"                                          \
    $arch_option						\
    $preinstall_args                                            \
    --hostname p2v.local                                        \
    --run-command 'hostname p2v.local'                          \
    --update                                                    \
    --install "$install"                                        \
    --root-password password:p2v                                \
    --upload "$datadir"/issue:/etc/issue                        \
    --upload "$datadir"/issue:/etc/issue.net                    \
    --mkdir /usr/bin                                            \
    --upload "$virt_p2v_binary":/usr/bin/virt-p2v               \
    --chmod 0755:/usr/bin/virt-p2v                              \
    --upload "$datadir"/launch-virt-p2v:/usr/bin/               \
    --chmod 0755:/usr/bin/launch-virt-p2v                       \
    --upload "$datadir"/p2v.service:/etc/systemd/system/        \
    --mkdir /etc/systemd/system/multi-user.target.wants         \
    --link /etc/systemd/system/p2v.service:/etc/systemd/system/multi-user.target.wants/p2v.service \
    --edit '/lib/systemd/system/getty@.service:
        s/^ExecStart=(.*)/ExecStart=$1 -a root/
    '                                                           \
    --edit '/etc/systemd/logind.conf:
        s/^[Login]/[Login]\nReserveVT=1\n/
    '                                                           \
    $upload                                                     \
    $extra_args                                                 \
    "${passthru[@]}"                                            \
    $final_args

# We have to do this so the cleanup() handler runs.
exit $?
